import Watcher from './watcher'

// 模板编译器
export default class Compiler {
  constructor(vm) {
    this.vm = vm
    this.$el = vm.$el
    this.compile(this.$el)
  }
  // 判断是否为文本节点
  isTextNode(node) {
    return node.nodeType === 3
  }
  // 判断是否为元素节点
  isElementNode(node) {
    return node.nodeType === 1
  }
  // 判断元素的属性是否是指令
  isDirective(attrName) {
    return attrName.startsWith('v-') || attrName.startsWith('@')
  }
  // 编译文本节点
  compileText(node) {
    // {{ data }} 正则
    let reg = /\{\{(.+?)\}\}/
    // 获取文本内容
    let value = node.textContent
    //
    if (reg.test(value)) {
      let key = RegExp.$1.trim()
      // 使用 data 里的数据替换 {{ data }}
      node.textContent = value.replace(reg, this.vm[key])
      //
      new Watcher(this.vm, key, newVaue => {
        node.textContent = newVaue
      })
    }
  }
  // 编译元素节点
  compileElement(node) {
    // 遍历元素的属性
    Array.from(node.attributes).forEach(attr => {
      // 提取属性名和属性值
      const { name, value } = attr
      // 判断是否为指令
      if (this.isDirective(name)) {
        // 判断 v-on 和 @
        if (name.startsWith('v-on:') || name.startsWith('@')) {
          let event = name.startsWith('v-on')
            ? name.substr('v-on:'.length)
            : name.substr('@'.length)
          this.onUpdater(event, node, value)
        } else {
          this.update(name.substr(2), node, value)
        }
      }
    })
  }
  /**
   * 执行对应的指令解析函数
   * @param {string} directive 指令名
   * @param {HTMLElement} node 节点
   * @param {any} key data 中的 key
   */
  update(directive, node, key) {
    let updater = this[directive + 'Updater']
    updater && updater.call(this, node, this.vm[key], key)
  }
  // 指令 v-on
  onUpdater(event, node, name) {
    node.addEventListener(event, e => {
      this.vm[name].call(this.vm, e)
    })
  }
  // 指令 v-text
  textUpdater(node, value, key) {
    node.textContent = value
    //
    new Watcher(this.vm, key, newValue => {
      node.textContent = newValue
    })
  }
  // 指令 v-model
  modelUpdater(node, value, key) {
    node.value = value
    //
    new Watcher(this.vm, key, newValue => {
      node.value = newValue
    })
    // 视图改变是数据跟随改变
    node.addEventListener('input', () => {
      this.vm[key] = node.value
    })
  }
  // 指令 v-html
  htmlUpdater(node, value, key) {
    node.innerHTML = value
    //
    new Watcher(this.vm, key, newValue => {
      node.innerHTML = newValue
    })
  }
  // 编译模板，文本节点和元素节点
  compile(el) {
    const { childNodes } = el
    Array.from(childNodes).forEach(node => {
      if (this.isTextNode(node)) {
        // 处理文本节点
        this.compileText(node)
      } else if (this.isElementNode(node)) {
        // 处理元素节点
        this.compileElement(node)
      }
      // 编译子节点
      if (node.childNodes && node.childNodes.length) {
        this.compile(node)
      }
    })
  }
}
